#include "sc/xml.h"

#include "libxml/parser.h"
#include "libxml/xmlmemory.h"
#include "libxml/relaxng.h"

using namespace sc::xml;

// RNG namespace
const xmlChar* rng::NS            = (const xmlChar*) "sc";
const xmlChar* rng::NS_VALUE      = (const xmlChar*) "http://relaxng.org/ns/structure/1.0";

// RNG Element
const xmlChar* rng::_element      = (const xmlChar*) "element";
const xmlChar* rng::_ref          = (const xmlChar*) "ref";
const xmlChar* rng::_zeroOrMore   = (const xmlChar*) "zeroOrMore";
const xmlChar* rng::_optional     = (const xmlChar*) "optional";

const xmlChar* rng::_text         = (const xmlChar*) "text";
const xmlChar* rng::_attribute    = (const xmlChar*) "attribute";
const xmlChar* rng::_data         = (const xmlChar*) "data";
const xmlChar* rng::_choice       = (const xmlChar*) "choice";
const xmlChar* rng::_value        = (const xmlChar*) "value";

const xmlChar* rng::_param        = (const xmlChar*) "param";

// RNG Attributes
const xmlChar* rng::_name         = (const xmlChar*) "name";

const xmlChar* rng::_type         = (const xmlChar*) "type";
const xmlChar* rng::_int          = (const xmlChar*) "int";
const xmlChar* rng::_integer      = (const xmlChar*) "integer";
const xmlChar* rng::_float        = (const xmlChar*) "float";
const xmlChar* rng::_string       = (const xmlChar*) "string";

const xmlChar* rng::_minInclusive = (const xmlChar*) "minInclusive";
const xmlChar* rng::_maxInclusive = (const xmlChar*) "maxInclusive";
const xmlChar* rng::_minExclusive = (const xmlChar*) "minExclusive";
const xmlChar* rng::_maxExclusive = (const xmlChar*) "maxExclusive";
const xmlChar* rng::_pattern      = (const xmlChar*) "pattern";


// SCC Element
const xmlChar* scc::_context         = (const xmlChar*) "sc-context";
const xmlChar* scc::_file            = (const xmlChar*) "file";
const xmlChar* scc::_xslt            = (const xmlChar*) "xslt";
const xmlChar* scc::_mmi             = (const xmlChar*) "mmi";
const xmlChar* scc::_element_label   = (const xmlChar*) "element-label";
const xmlChar* scc::_attribute_label = (const xmlChar*) "attribute-label";

// SCC Attributes
const xmlChar* scc::_title           = (const xmlChar*) "title";
const xmlChar* scc::_setup           = (const xmlChar*) "setup";
const xmlChar* scc::_rng             = (const xmlChar*) "rng";
const xmlChar* scc::_xsl             = (const xmlChar*) "xsl";
const xmlChar* scc::_xsltres         = (const xmlChar*) "xsltres";
const xmlChar* scc::_path            = (const xmlChar*) "path";
const xmlChar* scc::_for             = (const xmlChar*) "for";
const xmlChar* scc::_value           = (const xmlChar*) "value";
const xmlChar* scc::_default         = (const xmlChar*) "default";
const xmlChar* scc::_icon            = (const xmlChar*) "icon";
const xmlChar* scc::_error           = (const xmlChar*) "error";
const xmlChar* scc::_help            = (const xmlChar*) "help";
const xmlChar* scc::_type            = (const xmlChar*) "type";
const xmlChar* scc::_type_directory  = (const xmlChar*) "directory";
const xmlChar* scc::_type_file       = (const xmlChar*) "file";

/**
* Do a XSL transformation
*
* @param sXmlFile XML file name
* @param sXslFile XSL file name
* @param sXsltResFile XSL transformation result file name
*
* @return true if transformation was succesfull
*/
bool sc::xml::XslTransform(const wxString& sXmlFile, const wxString& sXslFile, const wxString& sXsltResFile)
{
	bool bXslt = false;
	xsltStylesheetPtr xslt = xsltParseStylesheetFile( (const xmlChar*) sXslFile.utf8_str().data() );
	if (xslt)
	{
		xmlDocPtr doc = xmlParseFile( sXmlFile.utf8_str() );
		if (doc)
		{
			xmlDocPtr res = xsltApplyStylesheet(xslt, doc, NULL);
			xsltSaveResultToFilename(sXsltResFile.utf8_str(), res, xslt, 0);
			xmlFreeDoc(res);
			xmlFreeDoc(doc);
			bXslt = true;
		}
		xsltFreeStylesheet(xslt);
	}
	return bXslt;
}

bool sc::xml::RngValidate(const wxString& sXmlFile, const wxString& sRngFile)
{
	bool bValid = false;
	xmlDocPtr xmlDoc = xmlReadFile(sXmlFile.utf8_str(), NULL, 0);
	if (xmlDoc)
	{
		xmlRelaxNGParserCtxtPtr rngCtx = xmlRelaxNGNewParserCtxt(sRngFile.utf8_str());
		xmlRelaxNGPtr schema = xmlRelaxNGParse(rngCtx);
		if (schema)
		{
			xmlRelaxNGValidCtxtPtr rngValidCtx = xmlRelaxNGNewValidCtxt(schema);
			if (rngValidCtx)
			{
				bValid = (0 == xmlRelaxNGValidateDoc(rngValidCtx, xmlDoc));
				xmlRelaxNGFreeValidCtxt(rngValidCtx);
			}
			xmlRelaxNGFree(schema);
		}
		xmlRelaxNGFreeParserCtxt(rngCtx);
		xmlFreeDoc(xmlDoc);
	}

	if (!bValid)
	{
		wxLogMessage(wxT("sc::xml::RngValidate(%s, %s) - INVALID"), sXmlFile.c_str(), sRngFile.c_str());
	}
	return bValid;
}
